
"""
抽象工厂模式是工厂方法模式的一种泛化，所以它能提供相同的好处：让对象的创建更 容易追踪；将对象创建与使用解耦；提供优化内存占用和应用性能的潜力。
创造一个游戏，或者想在应用中包含一个迷你游戏让用户娱乐娱乐。我们希望至少包含两个游戏， 一个面向孩子，一个面向成人。在运行时，基于用户输入，决定该创建哪个游戏并运行。游戏的 创建部分由一个抽象工厂维护。
"""


class Frog:
    def __init__(self, name):
        self.name = name

    def __str__(self):
        return self.name

    def interact_with(self, obstacle):
        print('{} the Frog encounters {} and {}!'.format(self,obstacle, obstacle.action()))

class Bug:
    def __str__(self):
        return 'a bug'

    def action(self):
        return 'eats it'

class FrogWorld:
    """
    类FrogWorld是一个抽象工厂，其主要职责是创建游戏的主人公和障碍物
    """
    def __init__(self, name):
        print(self)
        # self调用__str__魔法函数
        self.player_name = name

    def __str__(self):
        return '\n\n\t------ Frog World ———'

    def make_character(self):
        return Frog(self.player_name)

    def make_obstacle(self):
        return Bug()

class Wizard:
    def __init__(self, name):
        self.name = name

    def __str__(self):
        return self.name

    def interact_with(self, obstacle):
        print('{} the Wizard battles against {} and {}!'.format(self, obstacle, obstacle.action()))


class Ork:
    def __str__(self):
        return 'an evil ork'

    def action(self):
        return 'kills it'


class WizardWorld:
    """
    WizardWorld工厂类
    """
    def __init__(self, name):
        print(self)
        self.player_name = name

    def __str__(self):
        return '\n\n\t------ Wizard World ———'

    def make_character(self):
        return Wizard(self.player_name)

    def make_obstacle(self):
        return Ork()


class GameEnvironment:
    """
    类GameEnvironment是我们游戏的主入口。
    """
    def __init__(self, factory):
        self.hero = factory.make_character()
        self.obstacle = factory.make_obstacle()

    def play(self):
        self.hero.interact_with(self.obstacle)


def validate_age(name):
    """
    函数validate_age()提示用户提供一个有效的年龄。如果年龄无效，则会返回一个元组， 其第一个元素设置为False。如果年龄没问题，元素的第一个元素则设置为True,
    但我们真正关 心的是元素的第二个元素，也就是用户提供的年龄
    :param name:
    :return:
    """
    try:
        age = input('Welcome {}. How old are you? '.format(name))
        age = int(age)
    except ValueError as err:
        print("Age {} is invalid, please try again…".format(age))
        return (False, age)
    return (True, age)

def main():
    """
    main函数请求用户的姓名和年龄，并根据用户的年龄决定该玩 哪个游戏
    :return:
    """
    name = input("Hello. What's your name? ")
    valid_input = False
    while not valid_input:
        valid_input, age = validate_age(name)

    game = FrogWorld if age < 18 else WizardWorld

    environment = GameEnvironment(game(name))
    environment.play()

if __name__ == '__main__':
    main()
